package cate.game;

import cate.game.framework.share.ShareLogic;
import cate.game.util.GameSumInfo;
import cp.game.framework.*;
import cp.solution.util.concurrent.ThreadFactoryImpl;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
public class ManyGame extends ManyGameBase {

    public ManyGame(ManyGameConfig config, ConfigFromConsole configFromConsole, ApiCaller api, IProgramInfo programInfo, ILogcat logcat) {
        super(config, configFromConsole, api, programInfo, logcat);
    }

    private Map<Integer, GameBody> gameMap = new HashMap<>();

    public GameBody get(int srvId) {
        return gameMap.get(srvId);
    }

    public void put(int srvId, GameBody game) {
        game.process = this;
        gameMap.put(srvId, game);
    }

    /**
     * 在getall的时候做过滤， 达到开服时间的才算
     * @return list
     */
    public List<GameBody> getAll() {
        return gameMap.values().stream().filter(
                e -> (!e.lazyInit) && null != e.config.gs.getOpenTime() && e.config.gs.getOpenTime().getTime() < System.currentTimeMillis()
        ).collect(Collectors.toList());
    }

    public Collection<GameBody> getAllIncludeNotOpen() {
        return gameMap.values();
    }

    public GameBody getRandom() {
        List<GameBody> l = getAll();
        if(l.isEmpty()) {
            return null;
        }
        int ind = (int)(Math.random() * l.size());
        return l.get(ind);
    }

    /**
     * 执行定时任务
     * @param command
     */
    public void scheduleExecute(Function<GameBody, Runnable> command){
        for (GameBody game : getAll()) {
            Runnable runable = command.apply(game);
            if(gameScheduleExecutors != null){
                getGameScheduleExecutor(game.config.srvId).execute(runable);
            }else{
                runable.run();
            }
        }
    }

    /**
     * gamesrv定时任务
     * @param srvId srvid
     * @return es
     */
    public ExecutorService getGameScheduleExecutor(int srvId){
        return gameScheduleExecutors[gameIdx.get(srvId)];
    }
    private ExecutorService[] gameScheduleExecutors;
    public void initGameScheduleExecutors(int[] srvIds){
        if(gameScheduleExecutors == null && srvIds.length > 0){
            gameIdx = new HashMap<>();
            gameScheduleExecutors = new ExecutorService[srvIds.length];
            for(int i=0; i<srvIds.length; ++i){
                gameIdx.put(srvIds[i], i);
                gameScheduleExecutors[i] = Executors.newSingleThreadExecutor(new ThreadFactoryImpl("game-"+srvIds[i]+"-sche"));
            }
        }
    }
    private Map<Integer,Integer> gameIdx;


    //lazy executor
    private ScheduledExecutorService lazyInitExecutor;
    public void lazyThreadStart(){
        if(lazyInitExecutor == null){
            lazyInitExecutor = Executors
                    .newSingleThreadScheduledExecutor(new ThreadFactoryImpl("lazyInitThread"));
            //运维可能会改开服时间，所以用定时check的方式，而不是固定delay的方式
            lazyInitExecutor.scheduleAtFixedRate(() -> {
                gameMap.values().stream().filter(e -> e.lazyInit).forEach(e -> {
                    try {
                        Date openTime = e.config.gs.getOpenTime();
                        if(openTime != null && System.currentTimeMillis() >= openTime.getTime()){
                            log.info("game{}开始初始化",e.config.srvId);
                            e.starLazyInit();
                            e.lazyInit = false;
                        }
                    } catch (Exception exception) {
                        log.error("lazy thread exception:",exception);
                    }
                });
                boolean none = gameMap.values().stream().noneMatch(e -> e.lazyInit);
                if(none){
                    new Thread(() -> {
                        try{
                            Thread.sleep(5000);
                            lazyInitExecutor.shutdown();
                        }catch(Exception e){
                            log.error("",e);
                        }
                    }).start();
                }
            }, 60, 5, TimeUnit.SECONDS);
        }
    }

    public void shutdown(){
        if(lazyInitExecutor != null){
            lazyInitExecutor.shutdownNow();
        }
        if(gameScheduleExecutors != null){
            for(ExecutorService es : gameScheduleExecutors){
                es.shutdown();
            }
        }
        log.info("已关闭线程池");
    }

    public void checkShutdown() {
        Collection<GameBody> all = this.getAllIncludeNotOpen();
        int nRun = all.size();
        if(nRun <= 0) {
            return;
        }
        for(GameBody game : all) {
            if(!game.shutdownDone) {
                return;
            }
        }
        log.info("{}个GameBody都被shutdown了，进程即将退出", nRun);
        Runtime.getRuntime().halt(0);
    }

    public GameSumInfo sum() {
        return new GameSumInfo().read(this);
    }
}
